/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


package edu.uoc.tfc.exuoc.controladors;

import edu.uoc.tfc.exuoc.config.Config;
import edu.uoc.tfc.exuoc.utils.seguretat.InjeccioCodi;

import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.Transaction;
import org.hibernate.Session;
import org.hibernate.Query;

import java.io.UnsupportedEncodingException;
import org.hibernate.HibernateException;
import edu.uoc.tfc.exuoc.errors.BuitException;

import java.io.Serializable;
import java.util.Date;

//Test
import edu.uoc.tfc.exuoc.model.Usuari;
import edu.uoc.tfc.exuoc.model.Grup;
import edu.uoc.tfc.exuoc.model.Contenidor;
import edu.uoc.tfc.exuoc.model.Item;
import edu.uoc.tfc.exuoc.utils.Eines;
import edu.uoc.tfc.exuoc.errors.NoExisteixException;


/**
 *
 * @author emoreno
 */
            //TODO:14-11-2011:Emili: Caldria fer una interficie comuna per tots
            //els gestors

public class GestorBDD implements Serializable{

    private static final ThreadLocal sessio=new ThreadLocal();
    private Transaction trans;

    private GestorLogs  log=GestorLogs.getLogger(this.getClass().getName());


    protected GestorBDD() {
        //sessio= HibernateUtils.getSessionFactory().openSession();

    }

    private static Session getSessio(){

       // GestorLogs.getLogger(GestorBDD.class.getName())
       //         .error("getSessio()_1: ");
        Session sessi=(Session) GestorBDD.sessio.get();
       // GestorLogs.getLogger(GestorBDD.class.getName())
       //         .error("getSessio()_2: ");
        try{
            if (sessi==null){
                sessi=HibernateUtils.getSessionFactory().openSession();
               // GestorLogs.getLogger(GestorBDD.class.getName())
               // .error("getSessio()_3: ");
               // sessi=HibernateUtils.getSessionFactory().getCurrentSession();
                GestorBDD.sessio.set(sessi);
               //  GestorLogs.getLogger(GestorBDD.class.getName())
               // .error("getSessio()_4: ");
            }
        }catch(HibernateException ex){
           // GestorLogs.getLogger(GestorBDD.class.getName())
           //     .error("getSessio()_5: ");
            ex.printStackTrace();

        }catch(java.lang.Throwable ex){
           // GestorLogs.getLogger(GestorBDD.class.getName())
           //     .error("getSessio()_6: ");
            GestorLogs.getLogger(GestorBDD.class.getName())
                    .error("NO s'ha pogut crear una sessió: "
                    +ex.getLocalizedMessage());
        }

        return sessi;
    }

   /* @Override
    protected void finalize() throws Throwable {
        this.close();
        HibernateUtils.getSessionFactory().close();
        super.finalize();
    }
*/



    /***************************************************************************
     *      Mètodes de control de les transaccions
     *      Només accessibles des dels altres Gestors de dades DAO
     **************************************************************************/
    private Transaction begin() throws BuitException{
        Transaction t=null;
            try {

                //getSessio().setCacheMode(CacheMode.IGNORE);
                t=getSessio().beginTransaction();
            }catch (NullPointerException e){
                this.log.error("GBDD:begin:"+e.getLocalizedMessage());
                throw new BuitException("No es pot crear una transacció per no "
                        +"tenir sessió");
            }
        if (t.equals(null)){
            throw new BuitException("No s'ha generat cap transacció");
        }else trans=t;
        return t;
    }



    protected void close() {

        //if (getSessio().isConnected()) {
        if (getSessio()!=null){
                if (getSessio().isOpen()) {
                    try {
                        if (trans!=null){
                            if (trans.isActive() ) trans.commit();
                        }
                        getSessio().flush();
                        trans=null;
                        //Emili:09-10-11: getSessio().close();
                        //Emili:08-12-11:Es torna a activar
                        getSessio().close();
                        sessio.set(null);
                    }catch(HibernateException e){
                        this.log.info("GBDD:close:Error tancant la sessio de "
                                +"la base de dades."+e.getLocalizedMessage());
                    }
                }
        }
    }

     protected Transaction crearTrans(){
        Transaction t=null;
        try {
            this.begin();
            if (this.trans==null) {
                t=getSessio().beginTransaction();
                if (t!=null) this.trans=t;
            }
        }catch(HibernateException e){
               this.log.info("createTrans:Error creant la transacció."+e.getLocalizedMessage());
        }catch(BuitException e){
               this.log.info("createTrans: tenim valors buits."+e.getLocalizedMessage());
           }
        return t;
    }

    private void commit() {
        try {
            //Transaction t=this.crearTrans();
            if (trans!=null) trans.commit();
             else
                log.error("BDD:commit: No hi ha transacció.");
        }catch(HibernateException e){
        log.error("BDD:COMMIT:NO s'ha pogut fer el commit. "+e.getMessage());
        }

    }
    private void rollback() {
        try {
            if (trans!=null)
                trans.rollback();
            else
                log.error("BDD:Rollback:No tenim transcació.");

            //getSessio().getTransaction().rollback();
           //17-12-2011 getSessio().close();
            //17-11-2011 GestorBDD.sessio.set(null);

        }catch (HibernateException e){
            log.error("BDD:Rollback:No s'ha pogut fer un rollback."+ e.getMessage());
        }catch(NullPointerException e){
            log.error("BDD:Rollback:Valor null. No s'ha fet el rollback:"+ e.getMessage());
        }
    }

    private void flush(){
        try {

           //Emili:15-01-2012 if (trans!=null)
                getSessio().flush();
                getSessio().clear();

        }catch (HibernateException e){
            log.error("Flush:No s'ha pogut fer flush."+ e.getMessage());
        }catch(NullPointerException e){
            log.error("Flush:Valor null. No s'ha fet el flush:"+ e.getMessage());
        }
    }

    // Mètode per des-associcar una entitat de la seva representació relacional
    protected void evict(Object o){
         try {

            if (trans!=null)
                getSessio().evict(o);

        }catch (HibernateException e){
            log.error("Evict:No s'ha pogut fer Evict."+ e.getMessage());
        }catch(NullPointerException e){
            log.error("Evict:Valor null. No s'ha fet el Evict:"+ e.getMessage());
        }
    }

    //Mètode que re-assicia una entitat amb la la seva representació relacional
    protected void persist(Object o){
             try {

            if (trans!=null)
                getSessio().persist(o);

             }catch (HibernateException e){
            log.error("persist:No s'ha pogut fer persist."+ e.getMessage());
        }catch(NullPointerException e){
            log.error("persist:Valor null. No s'ha fet el persist:"+ e.getMessage());
        }
    }

    /***************************************************************************
     * Mètodes bàsics de gestió amb la base de dades
     *
    ***************************************************************************/
    protected  Long afegir(Object ob)  throws HibernateException, BuitException{

        Long id=Config.valorNull;
        try{
            begin();
            id=(Long)getSessio().save(ob);

            commit();
            flush();
            //2 this.getSessio().flush();

        }catch (HibernateException e){
            rollback();
            //String[] llista= { ob.getClass().getCanonicalName(),e.getLocalizedMessage()};
            log.error("BDD:Afegir:No s'ha pogut afegir un objecte :"
                    +ob.getClass().getSimpleName());
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }catch (BuitException e){
            rollback();
            String[] llista= { ob.getClass().getCanonicalName(),e.getLocalizedMessage()};
            log.error("BDD:Afegir:VAlor null, No s'ha pogut afegir un objecte :"
                    +ob.getClass().getSimpleName());
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        
        }finally{
           // close();
        }
        return id;
    }

    protected  Long afegir(Class classe, Object ob)  throws HibernateException, BuitException{

        Long id=Config.valorNull;
        try{
            begin();
            id=(Long)getSessio().save(classe.getCanonicalName(), ob);
            commit();
            flush();
            //2 this.getSessio().flush();

        }catch (HibernateException e){
            rollback();
            String[] llista= { ob.getClass().getSimpleName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut afegir l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }catch (BuitException e){
            rollback();
            String[] llista= { classe.getSimpleName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut afegir l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }finally{
           // close();
        }
        return id;
    }

    protected void eliminar(Object ob) throws HibernateException, BuitException{
        try{
            begin();
            getSessio().delete(ob);
            commit();
            flush();
            //2 this.getSessio().flush();
        }catch (HibernateException e){
            rollback();
            String[] llista= { ob.getClass().getSimpleName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut eliminar l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }catch (BuitException e){
            rollback();
            String[] llista= { ob.getClass().getSimpleName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut eliminar l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }finally{
           // close();
        }
    }

    /**
     *
     * @param elimina, Objecte a ser eliminat
     * @param arrel, Objecte d'on s'elimina el primer
     * @throws HibernateException
     * @throws BuitException
     */

    protected void eliminar(Object elimina, Object arrel) throws HibernateException, BuitException{
        try{
            begin();

            //filtre per la primera E-R Contenidor-Item
            if (arrel instanceof Contenidor){
                Contenidor c=(Contenidor)arrel;
                c.getItems().remove((Item)elimina);

            }
            commit();
            flush();
            //2 this.getSessio().flush();
        }catch (HibernateException e){
            rollback();
            String[] llista= { elimina.getClass().getSimpleName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut eliminar l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }catch (BuitException e){
            rollback();
            String[] llista= { elimina.getClass().getSimpleName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut eliminar l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }catch(NullPointerException e){
            rollback();
            log.error("No s'ha pogut eliminar l'objecte indicat per haver-hi un valor null");
            throw new BuitException ("No s'ha pogut eliminar l'objecte indicat per haver-hi un valor null");
        }
        finally{
           // close();
        }
    }


    /**
     * TODO:2011-26-11:Emili Antoni:  Cal afegir un mètode per eliminar
     *      identificant a l'objecte per id. Però de moment no cal
     */
    @Deprecated
    protected void eliminar(Class classe, Long id) throws HibernateException{
        //TODO
    }


    protected  void modificar(Object ob)  throws HibernateException, BuitException  {
      try{
            begin();
            /*getSessio().flush();
            getSessio().refresh(ob);
            getSessio().update(ob);*/
            //this.log.info("GestorBDD: "+ob.toString());
            getSessio().update(ob);
            log.info("GBD:modificar: Objecte a modificar: "
                    +ob.getClass().getSimpleName()+". Dades:"+ob.toString());
            this.commit();
            this.evict(ob);
            this.flush();
           //19 22-12 ob=null;


      }catch (HibernateException e){
            rollback();
            String[] llista= { ob.getClass().getName(),e.getMessage()};
            log.error("No s'ha pogut modificar l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
      }catch (BuitException e){
            rollback();
            String[] llista= { ob.getClass().getName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut modificar l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw new BuitException("L'objecte indicat no s'ha pogut modificar. "+ob.toString());
        }catch (Exception e){
            rollback();
            log.error("Error a la modificació: "+e.getLocalizedMessage());
        }
      finally{
            //close();
      }
      //return ob;

    }

    /**************************************************************
    /**************************************************************
     *  Mètodes bàsics de consulta
     **************************************************************/

    protected int quants(Class classe) throws HibernateException, BuitException {
        int num=Config.valorNullInt;
        String HQL="select count(*) from "+classe.getSimpleName();
        Query consulta;
        String rs=Config.valorNullStr;

        try{
            begin();
            consulta=getSessio().createQuery(HQL);
            //Eines.escriu(HQL);
            consulta.setComment(HQL);
            num=Integer.parseInt(consulta.uniqueResult().toString());

            commit();
        }catch (HibernateException e){
            rollback();
            log.error("GBDD:Quants:No s'ha pogut obtenir el nombre d'elements "+
                    "demanat. Classe: "+classe.getSimpleName());
            //Emili 12:01-2012: throw e;
            num=0;

        }catch (NullPointerException e){
            rollback();
            log.error("GBDD:Quants:No s'ha pogut obtenir la quantitat de/d` "+
                    classe.getSimpleName()+". "+e.getLocalizedMessage());
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            //Emili 12-01-2012: throw new BuitException("GBDD:Quants: Possiblement la llista " +
            //Emili 12-01-2012:         "sigui buida. Classe"+classe.getSimpleName()+". "
            //Emili 12-01-2012:         +e.getLocalizedMessage());
            num=0;
        }

        return num;
    }

    /**
     * Retorna el nombre d'elements de la classe donada que tenen per valor segons la
     * comparacio amb el camp donat. Cal tenir present que la base de dades
     * distingueix entre maiúscles i minúscules
     *
     * @param classe
     * @param camp
     * @param cmp
     * @param valor
     * @return
     * @throws HibernateException
     * @throws BuitException
     */
    protected int quants(Class classe,String camp, String cmp, Object valor) throws HibernateException, BuitException {
        int num=Config.valorNullInt;
        String HQL="select count(*) from "+classe.getSimpleName();
        HQL+=" taula where ";
        if (!(valor instanceof Date))
            HQL+="UPPER(taula."+camp+") ";
        else {
            HQL+="taula."+camp+" ";
        }
        HQL+=cmp+" "+this.parsejarPerSQL(valor,cmp);
        //Eines.escriu(HQL);
        Query consulta;
        String rs=Config.valorNullStr;

        try{
            begin();
            consulta=getSessio().createQuery(HQL);
            consulta.setComment(HQL);
            num=Integer.parseInt(consulta.uniqueResult().toString());

            commit();
        }catch (HibernateException e){
            rollback();
            String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
            log.error("GBDD:Quants:2:No s'ha pogut obtenir el nombre d'elements. "+
                    "demanat. Classe: "+classe.getSimpleName());
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;

        }catch (NullPointerException e){
            rollback();
           log.error("GBDD:Quants:No s'ha pogut obtenir la quantitat de/d` "+
                    classe.getSimpleName()+". "+e.getLocalizedMessage());
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw new BuitException("Possiblement la llista sigui buida");
        }finally{
           // close();
        }
        return num;
    }

    protected int nombreVisites(Long id,Class classe) throws HibernateException, NoExisteixException, BuitException{
        int visites=0;

        String HQL="select c.visites from "+classe.getSimpleName()+" as c  where c.id = :id";

        Query consulta;

        try{
            begin();
            consulta=getSessio().createQuery(HQL);
            consulta.setLong("id", id);
            consulta.setComment("Nombre de visites "+classe.getSimpleName());
            consulta.setMaxResults(1);
            visites=(Integer)consulta.uniqueResult();
            commit();


        }catch (HibernateException e){
            rollback();
            String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut obtenir el nombre de visites de ({}) , {} ",llista);
            throw e;

        } catch (NullPointerException e){
            rollback();
            String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut trobar l'entitat ({}) , {} ",llista);
            throw new  NoExisteixException("No s'ha pogut trobar l'entitat amb id :"+id.toString(),this.getClass());

        }/*catch (BuitException e){
            rollback();
            String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut obtenir el nombre de visites de l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }*/finally{
            //close();
        }

        return visites;
    }

    protected int augmentaVisites(Long id, Class classe) throws HibernateException,NoExisteixException, BuitException {
        int visites =0;

        String HQL="update "+classe.getSimpleName()+" set visites = visites + 1 where id = :id";

        Query consulta;
        String rs=Config.valorNullStr;
        Eines.escriu(classe.getSimpleName());
        try{
            begin();
            consulta=getSessio().createQuery(HQL);
            consulta.setLong("id", id);
            consulta.setComment("Augmentar el nombre de visites "+classe.getSimpleName()+": +1");

            int filesCanviades=consulta.executeUpdate();
            commit();
            flush();
            if (filesCanviades <1 ) throw new NoExisteixException("id :"+id.toString(),this.getClass());
            else {
                try{
                    visites=this.nombreVisites(id, classe);
                }catch(NoExisteixException e){
                    String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
                    log.error("No s'ha pogut actualitzar el nombre de visites de ({}) , {} ",llista);
                    throw e;
                }
            }
        }catch (HibernateException e){
            rollback();
            String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut actualitzar el nombre de visites de ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        } catch (NoExisteixException e){
            rollback();
            String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut actualitzar el nombre de visites de ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }catch (BuitException e){
            rollback();
            String[] llista= { classe.getCanonicalName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut augmentar el nombre de visites l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }finally{
            //close();
        }
        return visites;
    }


    protected Object llegir(Class classe,Long id)  throws HibernateException, BuitException {

        Object obj=null;
        try {
            trans=begin();
            getSessio().flush();
            obj=(Object)getSessio().load(classe, id);//.get(classe, new Long(id));

            commit();

        }catch (HibernateException e){
            rollback();
            log.error("BDD:llegir:No s'ha pogut llegir l'objecte "
                    +classe.getSimpleName()+", id:"+id+". "+e.getLocalizedMessage());
            throw e;
            //if (classe=="grup".toString()) return (Grup)obj;
            //if ("usuari".toString().toLowerCase()==classe) return (Usuari)obj;
        }/*catch (BuitException e){
            //rollback();
            String[] llista= { classe.getName(),e.getLocalizedMessage()};
            log.error("No s'ha pogut llegir l'objecte ({}) , {} ",llista);
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw e;
        }*/catch (NullPointerException e){
             rollback();
            if (id==null) log.error("GBD:Llegir:Id null, objecte"
                    +classe.getSimpleName()+". "+e.getLocalizedMessage());
            if (classe==null) log.error("GBD:Llegir:classe null, objecte"+id+". "
                    +e.getLocalizedMessage());
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            //throw e;
        }finally{
          //  close();
        }
        //return classe.cast(obj);
        return obj;
    }

    private String parsejarPerSQL(Object valor,String condicio) throws BuitException {
        String cad=Config.valorNullStr;
        InjeccioCodi filtre = new InjeccioCodi();

        try {
            if (valor instanceof Integer) cad=valor.toString();
                else if (valor instanceof Long) cad=((Long)valor).toString();
                    //Si tenim una data , aquesta segur que és correcte per ser,
                    //el valor, del tipus data. Cal formatejar-lo com si fos una
                    //cadena.
                    else if (valor instanceof Date){
                        cad="'"+Eines.formatejarData((Date)valor)+"'";
                    }else{
                        cad="UPPER('"+filtre.netejar(valor.toString());
                        if ("like".equals(condicio.trim()) ) cad+="%";
                        cad+="')";


                    }

        }catch(Exception e){
            throw new BuitException("no es pot realitzar el casting per llegir de :"+valor.getClass().getSimpleName());
        }
        return cad;
    }


    protected Object llegir(Class classe,String nomCamp, Object valor)  throws HibernateException, BuitException, UnsupportedEncodingException {

        InjeccioCodi filtre = new InjeccioCodi();
        Object obj=null;

        obj=this.llegirWhere(classe, filtre.netejar(nomCamp), valor);
        return classe.cast(obj);
    }

    private Object llegirWhere(Class classe,String nomCamp, Object valor)  throws HibernateException, BuitException {

        Object obj=null;
        String cadValor=this.parsejarPerSQL(valor,"=");
        try {

            String HQL="from "+classe.getSimpleName()+" taula where ";
            if (!(valor instanceof Date))
            HQL+="UPPER(taula."+nomCamp+") ";
        else {
            HQL+="taula."+nomCamp+" ";
        }
         HQL+="= "+cadValor;

            begin();
           //Eines.escriu(HQL);
            Query query = getSessio().createQuery(HQL);
            query.setMaxResults(1);
            obj=query.uniqueResult();
            commit();

            //getSessio().flush();

        }catch (HibernateException e){
            rollback();
           // String[] llista= { classe.getSimpleName(),String.valueOf(nomCamp),String.valueOf(cadValor)};
            log.error("BDD:Llegir: No s'ha pogut llegir un objecte"
                    +classe.getSimpleName()+" , pel camp:"+nomCamp+" amb valor"
                    +String.valueOf(valor));
            throw e;
            //if (classe=="grup".toString()) return (Grup)obj;
            //if ("usuari".toString().toLowerCase()==classe) return (Usuari)obj;
        }
        if (obj==null) {
            rollback();
            String[] llista= { String.valueOf(cadValor),nomCamp,classe.getName()};
            log.info("BDD:llegir No s'ha trobat cap valor:"
                    +String.valueOf(cadValor)+" pel camp: "+
                    nomCamp+"  de la taula "+classe.getSimpleName());
            //throws new Exception("No s'ha fet la petició sobre: "+ob.toString(),e);
            throw new BuitException("");
        }

        return classe.cast(obj);
    }

    protected List<?> Llista(Class classe,int ini, int fi,String campOrdre,
            String ordre)  throws HibernateException, BuitException{
        List<?> it=null;
        if ((fi-ini)<=0) {
            log.error("BDD:Llista:El valor del rang no és correcte per: "+classe.getSimpleName());
            throw new BuitException("BDD:Llista:El valor del rang no és correcte per: "+classe.getSimpleName());
        }
        try {
            //log.info("BDD:Llista(,,,,):");
            begin();
            //log.info("BDD:Llista(,,,,):Despres de l being");
            String nomTaula = classe.getSimpleName();
            //String HQL="from "+nomTaula+" taula order by taula.datapub "+ordre;
            String HQL="from "+nomTaula+" taula order by taula."+campOrdre+" "+ordre;

            Query query = getSessio().createQuery(HQL).setReadOnly(true);
            query.setFirstResult(ini);
            query.setMaxResults(fi-ini);
            //TransactionProxyFactoryBean
            it = (List<?>)query.list();
            //19-12_1:commit();
            //getSessio().flush();
            //log.info("BDD:Llista(,,,,):delspres del query");
        }catch(HibernateException e){
            //19-12_1:rollback();
            //String[] llista= { classe.getClass().getName()};
            log.error("GBD:llista1:No s'ha pogut obtenir la llista d'objectes :"
                    +classe.getSimpleName()+". "+e.getLocalizedMessage());
            throw e;
        }catch (NullPointerException e){
            //rollback();
            log.error("GBD:llista1:llista buida d'objectes, "+
                    classe.getSimpleName()+"."+e.getLocalizedMessage());
            throw new BuitException("GBD:llista1:llista buida d'objectes, "
                    +e.getLocalizedMessage());
        }catch (IndexOutOfBoundsException ex) {
            log.error("GBD:llista1:Error: La llista d'elements "
                    +classe.getSimpleName()+"es troba fora de rang. "
                    +ex.getLocalizedMessage());
            throw new BuitException("GBD:llista1:Error: La llista d'elements "
                    +classe.getSimpleName()+"es troba fora de rang. "
                    +ex.getLocalizedMessage());
        }
        return it;
    }

    protected List<?> Llista(Class classe, String campCerca, String compara,
            Object cadenaCerca, int ini, int fi,String campOrdre,String ordre)
            throws HibernateException, BuitException{
        List<?> it=null;
        if ((fi-ini)<=0) {
            log.error("GBD:llista2:Rang no correcte per: "+classe.getSimpleName());
            throw new BuitException("El valor del rang no és correcte per: "
                    +classe.getSimpleName());
        }
        try {

            InjeccioCodi filtre=new InjeccioCodi();
            begin();
            String nomTaula = classe.getSimpleName();
            String camp=filtre.netejar(campCerca);
            String campValor=this.parsejarPerSQL(cadenaCerca,compara);
            String cordre=filtre.netejar(campOrdre);
            String ord=(ordre == null ? ordre= Config.valorNullStr :
                    ordre.equals(Config.ORDRE)?Config.ORDRE:Config.ORDRE_INVERS);


            //String HQL="from "+nomTaula+" taula order by taula.datapub "+ordre;
            String HQL="from "+nomTaula+" taula ";
            if (camp!=null|| !camp.isEmpty()){
                if (!(cadenaCerca instanceof Date))
                    HQL+=" where UPPER(taula."+camp+") "+compara+" "+campValor;
                else
                    HQL+=" where taula."+camp+" "+compara+" "+campValor;
            }
            HQL=HQL + " order by taula."+cordre+" "+ord;
            this.log.info("CADENA:   "+HQL);

            Query query = getSessio().createQuery(HQL).setReadOnly(true);
            query.setFirstResult(ini);
            query.setMaxResults(fi-ini);

            //TransactionProxyFactoryBean
            it = (List<?>)query.list();
            commit();

        }catch(HibernateException e){
            rollback();
            log.error("GBD:llista2:No s'ha pogut obtenir la llista d'objectes :"
                    +classe.getSimpleName()+"."+e.getLocalizedMessage());
            throw e;
        }catch (NullPointerException ex) {
                log.error("GBD:llista2:Error: La llista d'elements "
                        +classe.getSimpleName()+" és nul·la"
                        +ex.getLocalizedMessage());
                throw new BuitException("GBD:llista2:Error: La llista "
                        +"d'elements "+classe.getSimpleName()+" és nul·la."
                        +ex.getLocalizedMessage());
        }catch (BuitException e){
            //rollback();
            log.error("GBD:llista2:llista buida d'objectes "
                    +classe.getSimpleName()+"."+e.getLocalizedMessage());
            throw e;
        }catch (IndexOutOfBoundsException ex) {
               log.error("GBD:llista2:Error: La llista d'elements "
                        +classe.getSimpleName()+"es troba fora de rang. "
                        +ex.getLocalizedMessage());
               throw new BuitException("GBD:llista2:Error: La llista d'elements"
                        +classe.getSimpleName()+" es troba fora de rang. "
                        +ex.getLocalizedMessage());
        }
        return it;
    }


    protected List<?> Llista(Class classe)  throws HibernateException, BuitException{
        List<?> it=null;
        try {
          //log.info("BDD:Llista(Classe)");
            int quants=this.quants(classe);
            if (Integer.valueOf(quants).equals(null) )quants=0;
            Eines.escriu(quants);
            it=this.Llista(classe, 0, quants, "id",Config.ORDRE);
        //log.info("BDD:Llista(classe):despres");
            /*   begin();
            String nomTaula = classe.getSimpleName();
            String HQL="from "+nomTaula+" "+nomTaula.toLowerCase();
            Query query = getSessio().createQuery(HQL);

            it = (Iterator<Object>)query.iterate();

            //commit();
            getSessio().flush();
            //close();
          *
          */
        }catch(HibernateException e){
            log.error("GBD:llista3:No s'ha pogut obtenir la llista d'objectes "
                    +classe.getSimpleName()+"."+e.getLocalizedMessage());
            throw e;
        }catch (BuitException e){
            //Emili:19-12_1:rollback();
            log.error("GBD:llista3:la llista d'objectes "
                   +classe.getSimpleName()+" es buida "+e.getLocalizedMessage());
            throw e;
        }
        catch (NullPointerException e){
            //Emili:19-12_1:rollback();
            log.error("GBD:llista3:la llista d'objectes "
                  +classe.getSimpleName()+" es buida "+e.getLocalizedMessage());
            throw new BuitException("GBD:llista3:la llista d'objectes "
                  +classe.getSimpleName()+"nul.la "+e.getLocalizedMessage());
        }
            return it;
    }
    /**
     *
     * @param classe, Classe d'entitat
     * @param ordre, asc/desc Pel camp datapub
     * @param quants, quants elements es volen, quants < Numentitats
     * @return llista filtrada
     * @throws HibernateException
     * @throws BuitException
     */
    protected List<?> Llista(Class classe,String ordre,int quants)
            throws HibernateException, BuitException{
        List<?> it=null;
        try {

            it=this.Llista(classe, 0, quants, "datapub", ordre);
        /*    begin();
            String nomTaula = classe.getSimpleName();
            String HQL="from "+nomTaula+" taula order by taula.datapub "+ordre;
            //Eines.escriu(HQL);
            Query query = getSessio().createQuery(HQL);
            query.setFirstResult(0);
            query.setMaxResults(quants);

            it = (Iterator<Object>)query.iterate();

            //commit();
            getSessio().flush();
            //close();
         *
         */
        }catch(HibernateException e){
            log.error("GBD:llista4:No s'ha pogut obtenir la llista d'objectes "
                    +classe.getSimpleName()+"."+e.getLocalizedMessage());
            throw e;
        }catch (BuitException e){
            rollback();
            log.error("GBD:llista4:la llista d'objectes "+classe.getSimpleName()
                    +" buida. "+e.getLocalizedMessage());
            throw e;
        }catch (NullPointerException e){
            rollback();
            log.error("GBD:llista4:la llista d'objectes "+classe.getSimpleName()
                    +" nul.la. "+e.getLocalizedMessage());
            throw e;
        }
            return it;
    }

    protected List<?> Llista(Class classe,String ordre,int quants,String camp)
            throws HibernateException, BuitException{
        List<?> it=null;
        try {

            it=this.Llista(classe, 0, quants, camp, ordre);

        }catch(HibernateException e){
            log.error("GBD:llista5:No s'ha pogut obtenir la llista d'objectes "
                    +classe.getSimpleName()+". "+e.getLocalizedMessage());
            throw e;
        }catch (BuitException e){
            rollback();
            log.error("GBD:llista5:llista d'objectes "+classe.getSimpleName()
                    +"."+"buida. "+e.getLocalizedMessage());
            throw e;
        }
        catch (NullPointerException e){
            rollback();
            log.error("GBD:llista5:llista d'objectes "+classe.getSimpleName()
                    +"."+"nul.la. "+e.getLocalizedMessage());
            throw e;
        }
            return it;
    }



    /***************************************************************
     *
     * TESTS
     *
     */
    private void testQuants(GestorBDD gd,Class classe){
        try {
            Eines.escriu(gd.quants(classe));
        } catch (HibernateException ex) {
            log.error("No s'ha pogut obtenir el nombre d'objectes:"+classe.getSimpleName()+" , {} ",ex.getLocalizedMessage());
        }catch (BuitException e) {

        }
    }

    private void testNombreVisites(GestorBDD gd,Class classe){
        Long id=2L;
        try {
            Eines.escriu(gd.nombreVisites(id, classe));
        } catch (HibernateException ex) {
            log.error("No s'ha pogut obtenir el nombre de visites ");
        } catch (NoExisteixException ex) {
             log.error("Error inesperat, Per l'entitat "+classe.getSimpleName()+" amb id "+id+" :{}", ex.getMessage());
        }catch (BuitException ex) {
             log.error("Error inesperat, Per l'entitat "+classe.getSimpleName()+" amb id "+id+" :{}", ex.getMessage());
        }
    }
    private void testAugmentaVisites(GestorBDD gd,Class classe) {
        Long id=2L;
        try {
            Eines.escriu(gd.augmentaVisites(id, classe));
        } catch (HibernateException ex) {
            log.error("No es pot actualitzar les visites de l'entitat "+classe.getSimpleName()+":{}", id);
        } catch (NoExisteixException ex) {
            log.error("L'entitat indicada no existeix, "+classe.getSimpleName()+" :{}", id);
        }catch (BuitException ex) {
            log.error("L'entitat indicada no existeix, "+classe.getSimpleName()+" :{}", id);
        }
    }

    private void testLlistat(GestorBDD gd,Class classe){
        //Contenidor obj=null;
        Object obj=null;
        try {
            Iterator it=gd.Llista(classe,Config.ORDRE,Config.nUltimsItems).iterator();
            while( it.hasNext()){
                //obj=(Contenidor)it.next();
                obj=it.next();
                try {
                    if (Class.forName(classe.getCanonicalName()).isInstance(obj)) {
                        Eines.escriu(obj);
                    }
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(GestorBDD.class.getCanonicalName()).log(Level.SEVERE, null, ex);
                }



                //Eines.escriu(obj.getNom()+", "+obj.getDatapub()+", "+obj.getId());
            }
        }catch(BuitException e){
                log.error("No s'ha pogut obtenir la llista d'objectes({}) , {} ",e.getLocalizedMessage());
            }
    }

    /**
     * TEST
     *
     */

    private void test(GestorBDD gd){
         //gd.testQuants(gd);
            //gd.testAugmentaVisites(gd);
            //gd.testNombreVisites(gd);
            //gd.testQuants(gd,Contenidor.class);
            //gd.testLlistat(gd,Item.class);
            Iterator it=null;

            try {
            it = gd.Llista(Item.class, "desc", 5).iterator();
            } catch (HibernateException ex) {
            Logger.getLogger(GestorBDD.class.getName()).log(Level.SEVERE, null, ex);
            } catch (BuitException ex) {
            Logger.getLogger(GestorBDD.class.getName()).log(Level.SEVERE, null, ex);
            }
            while (it.hasNext()){
                Item c=(Item)it.next();
                Eines.escriu(c);
            }
            try {
                Eines.escriu(Usuari.class.cast(gd.llegir(Usuari.class, "login", "emili")).getContrasenya());
            } catch (HibernateException ex) {
                Logger.getLogger(GestorBDD.class.getName()).log(Level.SEVERE, null, ex);
            } catch (BuitException ex) {
                Logger.getLogger(GestorBDD.class.getName()).log(Level.SEVERE, null, ex);
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(GestorBDD.class.getName()).log(Level.SEVERE, null, ex);
            }
    }

    private void testModif(GestorBDD gd){
        Contenidor c;
        c=(Contenidor)GestorBDD.getSessio().get(Contenidor.class, 1L);
        Eines.escriu(c);
        Eines.escriu(c.getItems().size());


    }



    public static void main (String[] args){

        GestorBDD gd= new GestorBDD();
        try {

            Eines.escriu("Items: "+gd.quants(Item.class));
            Eines.escriu("Contenidors que comencen per con*: "+gd.quants(Contenidor.class, "nom", "like", "con"));
            Eines.escriu("Contenidors: "+gd.quants(Contenidor.class));
            Eines.escriu("Usuaris: "+gd.quants(Usuari.class));


            Grup grup=null;
            grup=(Grup)gd.llegir(Grup.class, Config.AUTENTICAT);
            if (grup==null) Eines.escriu("ERROR: NO hem obtingut cap Grup");
            else Eines.escriu("Grup: "+grup);
            Eines.escriu();
            Iterator<Usuari> itG= (Iterator<Usuari>)grup.getUsuaris().iterator();
            Eines.escriu("Usuaris que pertanyen a: "+grup.getNom());
            Eines.escriu("----------------------------");
            while (itG.hasNext()){
                Usuari us2=itG.next();
                Eines.escriu(us2.getLogin()+","+us2.getNom()+","+us2.getDataalta());
            }
            Eines.escriu("----------------------------");

            Usuari usuari=(Usuari)gd.llegir(Usuari.class,1L);
            if (usuari==null) Eines.escriu("ERROR: N0 hem obtingut cap usuari");
            else Eines.escriu("Usuari:"+usuari.getLogin()+", Grup: "+usuari.getGrup().getNom());
            if (usuari.equals(null)) Eines.escriu("Valor null");
            else Eines.escriu(usuari.getLogin());//+"- "+usu.getGrup().getNom());

            Usuari u=null;
            Usuari u1=null;
            Iterator<Usuari> it=(Iterator<Usuari>)gd.Llista(Usuari.class).iterator();
            while (it.hasNext()){
                u=it.next();
                u1=it.next();
                if (u.equals(u1)){
                Eines.escriu("iguals:"+u.getId()+"- "+u.getLogin()+", "+u.getCognoms()+","+u.getNom()+". Grup:"+u.getGrup().getNom());
                }
            }

            Grup u2=null;
            Eines.escriu("Valor:"+u1.compareTo(u2));
        } catch (HibernateException ex) {
            Logger.getLogger(GestorBDD.class.getName()).log(Level.SEVERE, null, ex);
            Eines.escriu("Error d'hibernate");
        } catch (BuitException ex) {
            Logger.getLogger(GestorBDD.class.getName()).log(Level.SEVERE, null, ex);
            Eines.escriu("Error Valor buit");
        }finally{
            if (GestorBDD.getSessio().isOpen()){
                gd.close();
            }
        }

        gd.close();

}


}
/*
 * CD cd = new CD();

                cd.setTitle(titleField.getText());
                cd.setArtist(titleField.getText());
                cd.setCost(new Double(costField.getText()));
                cd.setPurchasedate(new Date());

                listModel.addCD(cd);
                Session session = null;
                try{
                    session = sessionFactory.openSession();
                    session.save(cd);
                }catch(Exception e){
                    System.out.println("Exception attemtping to Add CD: " + e.getMessage());

                }finally{
                    if(session != null && session.isOpen()){
                        session.flush();
                        session.close();
                    }
                }
 *
 *
 *
 */